<?php

namespace App\Supports\Payment;

use Illuminate\Support\Str;
use Illuminate\Support\Facades\Log;
use App\Supports\Payment\Channels\Spend;
use App\Supports\Payment\Channels\WxPay;
use App\Supports\Payment\Channels\AliPay;
use App\Supports\Payment\Channels\Balance;
use App\Supports\Payment\Channels\GoldCoin;
use App\Supports\Payment\Channels\GoldBean;
use App\Supports\Payment\Channels\Apple;
use App\Supports\Payment\Channels\AliBatch;
use App\Supports\Payment\Channels\AdaWxmini;
use App\Supports\Payment\Channels\AdaAlifuwu;
use App\Supports\Payment\Channels\SandWap;
use App\Supports\Payment\Contracts\MethodPay;
use App\Supports\Payment\Contracts\PayChannel;
use App\Supports\Payment\Contracts\MethodFind;
use App\Supports\Payment\Contracts\MethodQuery;
use App\Supports\Payment\Contracts\MethodRefund;
use App\Supports\Payment\Contracts\MethodTransfer;
use App\Supports\Payment\Contracts\MethodCallback;

/**
 * Class PayInit
 * @package App\Supports\Payment
 *
 * @method callbackAlipay($data)
 * @method callbackAdapay($data)
 *
 * @method payOrder($data)
 * @method callbackOrderPay($data)
 * @method refundOrder($object, $data)
 * @method callbackOrderRefund($data)
 * @method refundOrderItem($data)
 * @method callbackOrderItemRefund($data)
 *
 * @method payGoldCharge($data)
 * @method callbackGoldChargePay($data)
 *
 * @method payStorm($data)
 *
 * @method findActive()
 * @method transferWithdraw($data)
 * @method callbackWithdraw($data)
 * @method queryWithdraw($data)
 * @method queryWithdrawBatch($data)
 */
class PayInit
{
	protected $channel = null;

	protected $method = null;

	protected $prefix = 'App\\Supports\\Payment\\Methods\\';

	public function __construct($name)
	{
		$this->initChannel($name);
	}

	protected function initChannel($name)
	{
		if ($name === 'adawxmini') {
			app()->bind(PayChannel::class, AdaWxmini::class);
		} elseif ($name === 'adaalifuwu') {
			app()->bind(PayChannel::class, AdaAlifuwu::class);
		} elseif ($name === 'wxpay') {
			app()->bind(PayChannel::class, WxPay::class);
		} elseif ($name === 'alipay') {
			app()->bind(PayChannel::class, AliPay::class);
		} elseif ($name === 'alibatch') {
			app()->bind(PayChannel::class, AliBatch::class);
		} elseif ($name === 'goldcoin') {
			app()->bind(PayChannel::class, GoldCoin::class);
		} elseif ($name === 'goldbean') {
			app()->bind(PayChannel::class, GoldBean::class);
		} elseif ($name === 'apple') {
			app()->bind(PayChannel::class, Apple::class);
		} elseif ($name === 'balance') {
			app()->bind(PayChannel::class, Balance::class);
		} elseif ($name === 'sandwap') {
			app()->bind(PayChannel::class, SandWap::class);
		}
		$this->channel = app(PayChannel::class);

	}

	protected function initMethod($name)
	{
		$channel = $this->channel->getChannelName();
		$methodPath = $this->prefix.ucfirst($channel).'\\'.ucfirst($name);

		if (Str::startsWith($name, 'find')) {
			app()->bind(MethodFind::class, $methodPath);
			$this->method = app(MethodFind::class);
		} elseif (Str::startsWith($name, 'pay')) {
			app()->bind(MethodPay::class, $methodPath);
			$this->method = app(MethodPay::class);
		} elseif (Str::startsWith($name, 'cancel')) {
			app()->bind(MethodRefund::class, $methodPath);
			$this->method = app(MethodRefund::class);
		} elseif (Str::startsWith($name, 'refund')) {
			app()->bind(MethodRefund::class, $methodPath);
			$this->method = app(MethodRefund::class);
		} elseif (Str::startsWith($name, 'transfer')) {
			app()->bind(MethodTransfer::class, $methodPath);
			$this->method = app(MethodTransfer::class);
		} elseif (Str::startsWith($name, 'callback')) {
			app()->bind(MethodCallback::class, $methodPath);
			$this->method = app(MethodCallback::class);
		} elseif (Str::startsWith($name, 'query')) {
			app()->bind(MethodQuery::class, $methodPath);
			$this->method = app(MethodQuery::class);
		}
	}

	public function __call($name, $arguments)
	{
		$this->initMethod($name);

		if (!$this->channel or !$this->method) {
			abort(403, 'Payment channel or method does not be supported!');
		}

		$argFirst = isset($arguments[0]) ? $arguments[0] : null;
		$argSecond = isset($arguments[1]) ? $arguments[1] : null;

		return app(Pay::class)
			->setMethod($this->method)
			->$name($argFirst, $argSecond);
	}
}
